// Copyright (c) open_iA contributors
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once

#include "iASamplingMethod.h"

//! Generate a given number of parameter sets, randomly distributed (uniform distribution).
class iARandomSamplingMethod : public iASamplingMethod
{
public:
	QString name() const override;
	iAParameterSetsPointer parameterSets(std::shared_ptr<iAAttributes> parameter) override;
};

//! Uniform / Cartesian grid sampling.
//! This algorithm will yield a different amount of samples than specified (typically smaller).
//! Number of samples per parameter = 10 ^ ( log10(sampleCount) / (number of parameters) ) -> but a minimum of 2
//! Total number of samples = (Number of samples per parameter) * (number of parameters)
class iACartesianGridSamplingMethod : public iASamplingMethod
{
public:
	QString name() const override;
	void setSampleCount(int sampleCount, std::shared_ptr<iAAttributes> params) override;
	bool supportsSamplesPerParameter() const override;
	void setSamplesPerParameter(std::vector<int> samplesPerParameter) override;
	iAParameterSetsPointer parameterSets(std::shared_ptr<iAAttributes> parameter) override;
private:
	std::vector<int> m_samplesPerParameter;
};

//! Use latin hypercube sampling to generate the parameter sets.
//! This method works the same as distributing 8 queens on a chess board without any "overlaps" in rows or columns.
class iALatinHypercubeSamplingMethod : public iASamplingMethod
{
public:
	QString name() const override;
	iAParameterSetsPointer parameterSets(std::shared_ptr<iAAttributes> parameter) override;
};

//! Generates parameters around middle of given range for each parameter - "One at a time" sensitivity sampling.
//! For linear range, equivalent to Cartesian Grid sampler;
//! For logarithmic range, it starts in the middle, and expands outward.
class iALocalSensitivitySamplingMethod : public iASamplingMethod
{
public:
	QString name() const override;
	iAParameterSetsPointer parameterSets(std::shared_ptr<iAAttributes> parameter) override;
};

//! Generates a global sensitivity sampling by generating additional parameter sets
//! in a star shape around each parameter set generated by another given generator.
class MetaFilters_API iAGlobalSensitivitySamplingMethod : public iASamplingMethod
{
public:
	iAGlobalSensitivitySamplingMethod(std::shared_ptr<iASamplingMethod> otherGenerator, double delta);
	QString name() const override;
	iAParameterSetsPointer parameterSets(std::shared_ptr<iAAttributes> parameter) override;
private:
	std::shared_ptr<iASamplingMethod> m_baseGenerator;
	double m_delta;
};

class MetaFilters_API iAGlobalSensitivitySmallStarSamplingMethod: public iASamplingMethod
{
public:
	iAGlobalSensitivitySmallStarSamplingMethod(std::shared_ptr<iASamplingMethod> otherGenerator,
		double delta, int numSteps);
	QString name() const override;
	iAParameterSetsPointer parameterSets(std::shared_ptr<iAAttributes> parameter) override;

private:
	std::shared_ptr<iASamplingMethod> m_baseGenerator;
	double m_delta;
	int m_numSteps;
};

class MetaFilters_API iARerunSamplingMethod : public iASamplingMethod
{
public:
	iARerunSamplingMethod(QString const& fileName);
	iARerunSamplingMethod(iAParameterSetsPointer parameterSets, QString const& name);
	QString name() const override;
	iAParameterSetsPointer parameterSets(std::shared_ptr<iAAttributes> parameter) override;
private:
	QString m_name;
	iAParameterSetsPointer m_parameterSets;
};

//! Get the names of all sampling strategies that can be constructed via createSamplingMethod(...)
MetaFilters_API QStringList const & samplingMethodNames();

//! Construct a sampling strategy from the given parameters.
//! Note that most strategies don't require any parameters,
//! but to provide a generic interface for the construction
//! of all strategies, the parameters are required.
MetaFilters_API std::shared_ptr<iASamplingMethod> createSamplingMethod(QVariantMap const & parameters);
